/**
 * @description: 动态加载css
 * @param {*} url
 * @return {*}
 */
export function loadCss(url) {
  let css = document.createElement('link');
  css.href = url;
  css.rel = 'stylesheet';
  css.type = 'text/css';
  document.head.appendChild(css);
}

/**
 * @description: 动态加载单一script
 * @param {*} src
 * @return {*}
 */
export function loadScript(src) {
  return new Promise((resolve, reject) => {
    let s = document.createElement('script');
    s.async = false;
    s.src = src;

    const loadEvent = (e) => {
      s.parentNode?.removeChild(s);
      s.removeEventListener('load', loadEvent, false);
      s.removeEventListener('error', errorEvent, false);
      resolve();
    };

    const errorEvent = (e) => {
      s.parentNode.removeChild(s);
      s.removeEventListener('load', loadEvent, false);
      s.removeEventListener('error', errorEvent, false);
      reject(e);
    };

    s.addEventListener('load', loadEvent, false);
    s.addEventListener('error', errorEvent, false);

    document.body.appendChild(s);
  });
}

/**
 * @description: 动态加载资源（js、css）
 * @param {*} list  列表异步加载，对象同步加载，可随意嵌套，示例如下
  const arr = [
    {
      src: '/a.js',
      children: ['/a1.js', '/a2.js'],
    },
    {
      src: ['/1b.js', { src: '/2b.js', children: ['/2b1.js'] }],
      children: ['/b1.js', { src: '/b2.js', children: ['/b21.js'] }],
    },
    '/c.js',
  ];

  加载顺序示例为：[/a.js, /1b.js, /2b.js, /c.js] -> [/a1.js, /a2.js, /2b1.js] -> [/b1.js, /b2.js] -> [/b21.js]
 * @return {*}
 */
export function loadResource(list = []) {
  const loadFn = (url) => {
    if (url) {
      return /\.css$/.test(url) ? loadCss(url) : loadScript(url);
    }
    return null;
  };

  const promises = list.reduce((s, v) => {
    let p = null;

    if (typeof v === 'string') {
      p = loadFn(v);
    } else if (v?.src) {
      if (typeof v.src === 'string') {
        p = loadFn(v.src);
      } else if (Array.isArray(v.src)) {
        p = loadResource(v.src);
      }
    }

    if (p && Array.isArray(v?.children)) {
      p = p.then(() => loadResource(v.children));
    }

    s.push(p);

    return s;
  }, []);

  return new Promise((resolve, reject) => {
    Promise.allSettled(promises)
      .then((resArr) => {
        const rejected = resArr.filter((v) => v.status === 'rejected').map((v) => v.reason);

        if (rejected.length) {
          reject(rejected);
        } else {
          resolve();
        }
      })
      .catch(reject);
  });
}
